package com.it.smn.divide.interceptor;

import com.it.smn.divide.datasource.DynamicDataSourceRouter;
import com.it.smn.divide.datasource.ReadableDataSource;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.SimpleExecutor;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.logging.Log;
import org.apache.ibatis.logging.LogFactory;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.SqlCommandType;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.transaction.Transaction;
import org.mybatis.spring.transaction.SpringManagedTransaction;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import javax.sql.DataSource;
import java.lang.reflect.InvocationTargetException;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

/**
 * @author sunmannian
 * @ClassName com.it.smn.divide.interceptor.StatementHandlerInterceptor
 * @Date 2020/9/1 19:05
 * @Version V1.0
 * Description  <请输入一句话描述该类功能>
 * Copyright (C) 北京中电兴发科技有限公司  since 2020/9/1
 */
@Intercepts({@Signature(type = StatementHandler.class, args = {Connection.class, Integer.class}, method = "prepare")})
@Component()
public class StatementHandlerInterceptor implements Interceptor, InitializingBean, ApplicationContextAware {

    private static final Log log = LogFactory.getLog(StatementHandlerInterceptor.class);

    private static final String PREPARE_METHOD_NAME = "prepare";

    private DynamicDataSourceRouter dynamicDataSourceRouter;

    private ApplicationContext applicationContext;

    @Override
    public Object intercept(Invocation invocation) throws InvocationTargetException, IllegalAccessException, SQLException {
        MetaObject metaObject = SystemMetaObject.forObject(invocation.getTarget());
        // 查询SQL进行处理
        if (PREPARE_METHOD_NAME.equals(invocation.getMethod().getName()) &&
                SqlCommandType.SELECT == ((MappedStatement) metaObject.getValue("delegate.mappedStatement")).getSqlCommandType()) {
            Connection connection = dynamicDataSourceRouter.getReadDataSource().getConnection();
            // 获取原始的连接
            Connection original = (Connection) invocation.getArgs()[0];
            connection.setReadOnly(original.isReadOnly());
            connection.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);
            connection.setAutoCommit(original.getAutoCommit());
            // 替换链接
            invocation.getArgs()[0] = connection;
        }
        return invocation.proceed();
    }

    @Override
    public Object plugin(Object target) {
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {

    }


    @Override
    public void afterPropertiesSet() throws Exception {
        dynamicDataSourceRouter = applicationContext.getBean(DynamicDataSourceRouter.class);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }

    private Executor createNewExecutor(MetaObject metaObject) {
        Configuration configuration = (Configuration) metaObject.getValue("delegate.configuration");
        DataSource dataSource = ((ReadableDataSource) (dynamicDataSourceRouter.getReadDataSource())).getDataSource();
        Transaction transaction = new SpringManagedTransaction(dataSource);
        SimpleExecutor simpleExecutor = new SimpleExecutor(configuration, transaction);
//        if (configuration.isCacheEnabled()) {
//            return new CachingExecutor(simpleExecutor);
//        }
        return simpleExecutor;
    }
}
